#include "precom.h"
#include "Model.h"

using namespace std;

Model::Model()
{
	m_compiledModel = 0;
	m_box.Set(-4.f, -4.f, -4.f, 8.f, 8.f, 8.f);
}

Model::~Model()
{
	Clear();
}

void Model::CalculateBBox()
{
	std::list<Mesh*>::iterator iter = m_meshes.begin();
	m_box = Box::ZERO;
	while( iter != m_meshes.end() ) {
		m_box.EnlargeBBox((*iter)->m_bbox);
		++iter;
	}
}

bool Model::LoadModel(wchar_t* a_fileName)
{
	Clear();
	unsigned long ind = 0;
	while(a_fileName[ind] != '\0') ++ind;
	while(a_fileName[ind] != '.') --ind;
	++ind;
	if(a_fileName[ind] == '3')
		return Load3DSFile(a_fileName);
	if((a_fileName[ind] == 'o' || a_fileName[ind] == 'O')
		&& (a_fileName[ind+1] == 'b' || a_fileName[ind+1] == 'B')
		&& (a_fileName[ind+2] == 'j' || a_fileName[ind+2] == 'J') )
		return LoadObjFile(a_fileName);
	
	return BAD_FILE_FORMAT;	
}

bool Model::Load3DSFile(wchar_t* a_fileName)
{
	Load3DS loader;
	loader.Load(a_fileName, &m_meshes);
	CalculateBBox();
	return CompileModel();
}

bool Model::LoadObjFile(wchar_t* a_fileName)
{
	ObjLoader loader;
	loader.Load(a_fileName, &m_meshes);
	CalculateBBox();
	return CompileModel();
}

bool Model::CompileModel()
{
	std::list<Mesh*>::iterator iter;
	Mesh* tmp;
	float point[3];
	if(m_meshes.size() == 0) return false;
	if(m_compiledModel) {
		glDeleteLists(m_compiledModel, 3);
		m_compiledModel = 0;
	}
	m_compiledModel = glGenLists(3);
	if(m_compiledModel == 0) return false;
	//============================
	//	kompilacja WIREDFRAME
	iter = m_meshes.begin();
	glNewList(m_compiledModel, GL_COMPILE);
		//glColor3f(0.0f, 0.5f, 0.f);
		glBegin(GL_LINES);
		while(iter != m_meshes.end()) {
			tmp = *iter;
			for(unsigned long i= 0; i<tmp->m_triangles.size(); ++i) {
				glVertex3fv(tmp->m_vertices[tmp->m_normals[tmp->m_triangles[i].m_normals[0]].m_vertexNum].m_position);
				glVertex3fv(tmp->m_vertices[tmp->m_normals[tmp->m_triangles[i].m_normals[1]].m_vertexNum].m_position);
				glVertex3fv(tmp->m_vertices[tmp->m_normals[tmp->m_triangles[i].m_normals[1]].m_vertexNum].m_position);
				glVertex3fv(tmp->m_vertices[tmp->m_normals[tmp->m_triangles[i].m_normals[2]].m_vertexNum].m_position);
				glVertex3fv(tmp->m_vertices[tmp->m_normals[tmp->m_triangles[i].m_normals[2]].m_vertexNum].m_position);
				glVertex3fv(tmp->m_vertices[tmp->m_normals[tmp->m_triangles[i].m_normals[0]].m_vertexNum].m_position);
			}
			++iter;
		}
		glEnd();
	glEndList();

	//============================
	//	kompilacja SOLID
	iter = m_meshes.begin();
	glNewList(m_compiledModel+1, GL_COMPILE);
		//glColor3f(0.1f, 0.2f, 0.7f);
		glBegin(GL_TRIANGLES);
		while(iter != m_meshes.end()) {
			tmp = *iter;
			for(unsigned long i= 0; i<tmp->m_triangles.size(); ++i) {
				glNormal3fv( tmp->m_normals[tmp->m_triangles[i].m_normals[0]].m_normal );
				glVertex3fv(tmp->m_vertices[tmp->m_normals[tmp->m_triangles[i].m_normals[0]].m_vertexNum].m_position);
				glNormal3fv( tmp->m_normals[tmp->m_triangles[i].m_normals[1]].m_normal );
				glVertex3fv(tmp->m_vertices[tmp->m_normals[tmp->m_triangles[i].m_normals[1]].m_vertexNum].m_position);
				glNormal3fv( tmp->m_normals[tmp->m_triangles[i].m_normals[2]].m_normal );
				glVertex3fv(tmp->m_vertices[tmp->m_normals[tmp->m_triangles[i].m_normals[2]].m_vertexNum].m_position);
			}
			++iter;
		}
		glEnd();
	glEndList();

	//===========================
	//	kompilacja NORMALS
	float scale = m_box.GetMaxSize() / 40.0f;
	if(fabs(scale) < EPS) scale = 0.1f;
	iter = m_meshes.begin();
	glNewList(m_compiledModel+2, GL_COMPILE);
		//glColor3f(0.6f, 0.f, 0.f);
		glBegin(GL_LINES);
		while(iter != m_meshes.end()) {
			tmp = *iter;
			for(unsigned long i= 0; i<tmp->m_normals.size(); ++i) {
				glVertex3fv(tmp->m_vertices[tmp->m_normals[i].m_vertexNum].m_position);
				point[0] = tmp->m_vertices[tmp->m_normals[i].m_vertexNum].m_position[0] + tmp->m_normals[i].m_normal[0] * scale;
				point[1] = tmp->m_vertices[tmp->m_normals[i].m_vertexNum].m_position[1] + tmp->m_normals[i].m_normal[1] * scale;
				point[2] = tmp->m_vertices[tmp->m_normals[i].m_vertexNum].m_position[2] + tmp->m_normals[i].m_normal[2] * scale;
				glVertex3fv(point);
			}
			++iter;
		}
		glEnd();
	glEndList();

	return true;
}

void Model::Clear()
{
	Mesh* tmp = NULL;
	if(m_compiledModel) {
		glDeleteLists(m_compiledModel, 3);
		m_compiledModel = 0;
	}
	while( !m_meshes.empty() ) {
		tmp = m_meshes.back();
		m_meshes.pop_back();
		delete tmp;
		tmp = NULL;
	}
}